From d4f373e57d3916814110968c5ea1155a8d972b5a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Nov 2008 14:07:45 -0500 Subject: USB: usb-storage: add "quirks=" module parameter This patch (as1163b) adds a "quirks=" module parameter to usb-storage. This will allow people to make short-term changes to their unusual_devs list without rebuilding the entire driver. Testing will become much easier, and less-sophisticated users will be able to access their buggy devices after a simple config-file change instead of having to wait for a new kernel release. The patch also adds a documentation entry for usb-storage's "delay_use" parameter, which has been around for years but but was never listed among the kernel parameters. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 0b3f6711d2f1..8eb6e35405cd 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -91,6 +91,7 @@ parameter is applicable: SUSPEND System suspend states are enabled. FTRACE Function tracing enabled. TS Appropriate touchscreen support is enabled. + UMS USB Mass Storage support is enabled. USB USB support is enabled. USBHID USB Human Interface Device support is enabled. V4L Video For Linux support is enabled. @@ -2383,6 +2384,34 @@ and is between 256 and 4096 characters. It is defined in the file usbhid.mousepoll= [USBHID] The interval which mice are to be polled at. + usb-storage.delay_use= + [UMS] The delay in seconds before a new device is + scanned for Logical Units (default 5). + + usb-storage.quirks= + [UMS] A list of quirks entries to supplement or + override the built-in unusual_devs list. List + entries are separated by commas. Each entry has + the form VID:PID:Flags where VID and PID are Vendor + and Product ID values (4-digit hex numbers) and + Flags is a set of characters, each corresponding + to a common usb-storage quirk flag as follows: + c = FIX_CAPACITY (decrease the reported + device capacity by one sector); + i = IGNORE_DEVICE (don't bind to this + device); + l = NOT_LOCKABLE (don't try to lock and + unlock ejectable media); + m = MAX_SECTORS_64 (don't transfer more + than 64 sectors = 32 KB at a time); + r = IGNORE_RESIDUE (the device reports + bogus residue values); + s = SINGLE_LUN (the device has only one + Logical Unit); + w = NO_WP_DETECT (don't test whether the + medium is write-protected). + Example: quirks=0419:aaf5:rl,0421:0433:rc + add_efi_memmap [EFI; x86-32,X86-64] Include EFI memory map in kernel's map of available physical RAM. -- cgit v1.2.3 From 9ac39f28b5237a629e41ccfc1f73d3a55723045c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 12 Nov 2008 16:19:49 -0500 Subject: USB: add asynchronous autosuspend/autoresume support This patch (as1160b) adds support routines for asynchronous autosuspend and autoresume, with accompanying documentation updates. There already are several potential users of this interface, and others are likely to arise as autosuspend support becomes more widespread. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/power-management.txt | 22 +++++++-- drivers/usb/core/driver.c | 86 ++++++++++++++++++++++++++++++++++ drivers/usb/core/hub.c | 5 +- drivers/usb/core/usb.c | 1 + drivers/usb/core/usb.h | 1 + include/linux/usb.h | 9 ++++ 6 files changed, 117 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt index e48ea1d51010..ad642615ad4c 100644 --- a/Documentation/usb/power-management.txt +++ b/Documentation/usb/power-management.txt @@ -313,11 +313,13 @@ three of the methods listed above. In addition, a driver indicates that it supports autosuspend by setting the .supports_autosuspend flag in its usb_driver structure. It is then responsible for informing the USB core whenever one of its interfaces becomes busy or idle. The -driver does so by calling these three functions: +driver does so by calling these five functions: int usb_autopm_get_interface(struct usb_interface *intf); void usb_autopm_put_interface(struct usb_interface *intf); int usb_autopm_set_interface(struct usb_interface *intf); + int usb_autopm_get_interface_async(struct usb_interface *intf); + void usb_autopm_put_interface_async(struct usb_interface *intf); The functions work by maintaining a counter in the usb_interface structure. When intf->pm_usage_count is > 0 then the interface is @@ -330,10 +332,12 @@ associated with the device itself rather than any of its interfaces. This field is used only by the USB core.) The driver owns intf->pm_usage_count; it can modify the value however -and whenever it likes. A nice aspect of the usb_autopm_* routines is -that the changes they make are protected by the usb_device structure's -PM mutex (udev->pm_mutex); however drivers may change pm_usage_count -without holding the mutex. +and whenever it likes. A nice aspect of the non-async usb_autopm_* +routines is that the changes they make are protected by the usb_device +structure's PM mutex (udev->pm_mutex); however drivers may change +pm_usage_count without holding the mutex. Drivers using the async +routines are responsible for their own synchronization and mutual +exclusion. usb_autopm_get_interface() increments pm_usage_count and attempts an autoresume if the new value is > 0 and the @@ -348,6 +352,14 @@ without holding the mutex. is suspended, and it attempts an autosuspend if the value is <= 0 and the device isn't suspended. + usb_autopm_get_interface_async() and + usb_autopm_put_interface_async() do almost the same things as + their non-async counterparts. The differences are: they do + not acquire the PM mutex, and they use a workqueue to do their + jobs. As a result they can be called in an atomic context, + such as an URB's completion handler, but when they return the + device will not generally not yet be in the desired state. + There also are a couple of utility routines drivers can use: usb_autopm_enable() sets pm_usage_cnt to 0 and then calls diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 8c081308b0e2..23b3c7e79d4b 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1341,6 +1341,19 @@ void usb_autosuspend_work(struct work_struct *work) usb_autopm_do_device(udev, 0); } +/* usb_autoresume_work - callback routine to autoresume a USB device */ +void usb_autoresume_work(struct work_struct *work) +{ + struct usb_device *udev = + container_of(work, struct usb_device, autoresume); + + /* Wake it up, let the drivers do their thing, and then put it + * back to sleep. + */ + if (usb_autopm_do_device(udev, 1) == 0) + usb_autopm_do_device(udev, -1); +} + /** * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces * @udev: the usb_device to autosuspend @@ -1491,6 +1504,45 @@ void usb_autopm_put_interface(struct usb_interface *intf) } EXPORT_SYMBOL_GPL(usb_autopm_put_interface); +/** + * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter + * @intf: the usb_interface whose counter should be decremented + * + * This routine does essentially the same thing as + * usb_autopm_put_interface(): it decrements @intf's usage counter and + * queues a delayed autosuspend request if the counter is <= 0. The + * difference is that it does not acquire the device's pm_mutex; + * callers must handle all synchronization issues themselves. + * + * Typically a driver would call this routine during an URB's completion + * handler, if no more URBs were pending. + * + * This routine can run in atomic context. + */ +void usb_autopm_put_interface_async(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + int status = 0; + + if (intf->condition == USB_INTERFACE_UNBOUND) { + status = -ENODEV; + } else { + udev->last_busy = jiffies; + --intf->pm_usage_cnt; + if (udev->autosuspend_disabled || udev->autosuspend_delay < 0) + status = -EPERM; + else if (intf->pm_usage_cnt <= 0 && + !timer_pending(&udev->autosuspend.timer)) { + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, + round_jiffies_relative( + udev->autosuspend_delay)); + } + } + dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", + __func__, status, intf->pm_usage_cnt); +} +EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async); + /** * usb_autopm_get_interface - increment a USB interface's PM-usage counter * @intf: the usb_interface whose counter should be incremented @@ -1536,6 +1588,37 @@ int usb_autopm_get_interface(struct usb_interface *intf) } EXPORT_SYMBOL_GPL(usb_autopm_get_interface); +/** + * usb_autopm_get_interface_async - increment a USB interface's PM-usage counter + * @intf: the usb_interface whose counter should be incremented + * + * This routine does much the same thing as + * usb_autopm_get_interface(): it increments @intf's usage counter and + * queues an autoresume request if the result is > 0. The differences + * are that it does not acquire the device's pm_mutex (callers must + * handle all synchronization issues themselves), and it does not + * autoresume the device directly (it only queues a request). After a + * successful call, the device will generally not yet be resumed. + * + * This routine can run in atomic context. + */ +int usb_autopm_get_interface_async(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + int status = 0; + + if (intf->condition == USB_INTERFACE_UNBOUND) + status = -ENODEV; + else if (udev->autoresume_disabled) + status = -EPERM; + else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED) + queue_work(ksuspend_usb_wq, &udev->autoresume); + dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", + __func__, status, intf->pm_usage_cnt); + return status; +} +EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); + /** * usb_autopm_set_interface - set a USB interface's autosuspend state * @intf: the usb_interface whose state should be set @@ -1563,6 +1646,9 @@ EXPORT_SYMBOL_GPL(usb_autopm_set_interface); void usb_autosuspend_work(struct work_struct *work) {} +void usb_autoresume_work(struct work_struct *work) +{} + #endif /* CONFIG_USB_SUSPEND */ /** diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b19cbfcd51da..95fb3104ba4f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1374,8 +1374,9 @@ static void usb_stop_pm(struct usb_device *udev) usb_autosuspend_device(udev->parent); usb_pm_unlock(udev); - /* Stop any autosuspend requests already submitted */ - cancel_rearming_delayed_work(&udev->autosuspend); + /* Stop any autosuspend or autoresume requests already submitted */ + cancel_delayed_work_sync(&udev->autosuspend); + cancel_work_sync(&udev->autoresume); } #else diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 400fa4cc9a34..44f2fc750b6d 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -402,6 +402,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, #ifdef CONFIG_PM mutex_init(&dev->pm_mutex); INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); + INIT_WORK(&dev->autoresume, usb_autoresume_work); dev->autosuspend_delay = usb_autosuspend_delay * HZ; dev->connect_time = jiffies; dev->active_duration = -jiffies; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 9a1a45ac3add..b60ebb4de1a8 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -45,6 +45,7 @@ extern int usb_suspend(struct device *dev, pm_message_t msg); extern int usb_resume(struct device *dev); extern void usb_autosuspend_work(struct work_struct *work); +extern void usb_autoresume_work(struct work_struct *work); extern int usb_port_suspend(struct usb_device *dev); extern int usb_port_resume(struct usb_device *dev); extern int usb_external_suspend_device(struct usb_device *udev, diff --git a/include/linux/usb.h b/include/linux/usb.h index f72aa51f7bcd..859a88e6ce9c 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -398,6 +398,7 @@ struct usb_tt; * @urbnum: number of URBs submitted for the whole device * @active_duration: total time device is not suspended * @autosuspend: for delayed autosuspends + * @autoresume: for autoresumes requested while in_interrupt * @pm_mutex: protects PM operations * @last_busy: time of last use * @autosuspend_delay: in jiffies @@ -476,6 +477,7 @@ struct usb_device { #ifdef CONFIG_PM struct delayed_work autosuspend; + struct work_struct autoresume; struct mutex pm_mutex; unsigned long last_busy; @@ -513,6 +515,8 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); extern int usb_autopm_set_interface(struct usb_interface *intf); extern int usb_autopm_get_interface(struct usb_interface *intf); extern void usb_autopm_put_interface(struct usb_interface *intf); +extern int usb_autopm_get_interface_async(struct usb_interface *intf); +extern void usb_autopm_put_interface_async(struct usb_interface *intf); static inline void usb_autopm_enable(struct usb_interface *intf) { @@ -539,8 +543,13 @@ static inline int usb_autopm_set_interface(struct usb_interface *intf) static inline int usb_autopm_get_interface(struct usb_interface *intf) { return 0; } +static inline int usb_autopm_get_interface_async(struct usb_interface *intf) +{ return 0; } + static inline void usb_autopm_put_interface(struct usb_interface *intf) { } +static inline void usb_autopm_put_interface_async(struct usb_interface *intf) +{ } static inline void usb_autopm_enable(struct usb_interface *intf) { } static inline void usb_autopm_disable(struct usb_interface *intf) -- cgit v1.2.3 From c838ea4626d6e982489ff519f9ecf5e1649ca90b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 15 Dec 2008 10:40:06 -0500 Subject: USB: storage: make the "quirks=" module parameter writable This patch (as1190) makes usb-storage's "quirks=" module parameter writable, so that users can add entries for their devices at runtime with no need to reboot or reload usb-storage. New codes are added for the SANE_SENSE, CAPACITY_HEURISTICS, and CAPACITY_OK flags. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 7 ++ drivers/usb/storage/usb.c | 169 +++++++++++++++--------------------- 2 files changed, 76 insertions(+), 100 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 8eb6e35405cd..a58fc8b73398 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2396,14 +2396,21 @@ and is between 256 and 4096 characters. It is defined in the file and Product ID values (4-digit hex numbers) and Flags is a set of characters, each corresponding to a common usb-storage quirk flag as follows: + a = SANE_SENSE (collect more than 18 bytes + of sense data); c = FIX_CAPACITY (decrease the reported device capacity by one sector); + h = CAPACITY_HEURISTICS (decrease the + reported device capacity by one + sector if the number is odd); i = IGNORE_DEVICE (don't bind to this device); l = NOT_LOCKABLE (don't try to lock and unlock ejectable media); m = MAX_SECTORS_64 (don't transfer more than 64 sectors = 32 KB at a time); + o = CAPACITY_OK (accept the capacity + reported by the device); r = IGNORE_RESIDUE (the device reports bogus residue values); s = SINGLE_LUN (the device has only one diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 80e234bf4e50..4becf495ca2d 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -111,16 +111,10 @@ static unsigned int delay_use = 5; module_param(delay_use, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); -static char *quirks; -module_param(quirks, charp, S_IRUGO); +static char quirks[128]; +module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR); MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); -struct quirks_entry { - u16 vid, pid; - u32 fflags; -}; -static struct quirks_entry *quirks_list, *quirks_end; - /* * The entries in this table correspond, line for line, @@ -481,28 +475,80 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf) return 0; } +/* Works only for digits and letters, but small and fast */ +#define TOLOWER(x) ((x) | 0x20) + /* Adjust device flags based on the "quirks=" module parameter */ static void adjust_quirks(struct us_data *us) { - u16 vid, pid; - struct quirks_entry *q; - unsigned int mask = (US_FL_FIX_CAPACITY | US_FL_IGNORE_DEVICE | + char *p; + u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor); + u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct); + unsigned f = 0; + unsigned int mask = (US_FL_SANE_SENSE | US_FL_FIX_CAPACITY | + US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE | US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 | - US_FL_IGNORE_RESIDUE | US_FL_SINGLE_LUN | - US_FL_NO_WP_DETECT); - - vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor); - pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct); - - for (q = quirks_list; q != quirks_end; ++q) { - if (q->vid == vid && q->pid == pid) { - us->fflags = (us->fflags & ~mask) | q->fflags; - dev_info(&us->pusb_intf->dev, "Quirks match for " - "vid %04x pid %04x: %x\n", - vid, pid, q->fflags); + US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE | + US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT); + + p = quirks; + while (*p) { + /* Each entry consists of VID:PID:flags */ + if (vid == simple_strtoul(p, &p, 16) && + *p == ':' && + pid == simple_strtoul(p+1, &p, 16) && + *p == ':') break; + + /* Move forward to the next entry */ + while (*p) { + if (*p++ == ',') + break; } } + if (!*p) /* No match */ + return; + + /* Collect the flags */ + while (*++p && *p != ',') { + switch (TOLOWER(*p)) { + case 'a': + f |= US_FL_SANE_SENSE; + break; + case 'c': + f |= US_FL_FIX_CAPACITY; + break; + case 'h': + f |= US_FL_CAPACITY_HEURISTICS; + break; + case 'i': + f |= US_FL_IGNORE_DEVICE; + break; + case 'l': + f |= US_FL_NOT_LOCKABLE; + break; + case 'm': + f |= US_FL_MAX_SECTORS_64; + break; + case 'o': + f |= US_FL_CAPACITY_OK; + break; + case 'r': + f |= US_FL_IGNORE_RESIDUE; + break; + case 's': + f |= US_FL_SINGLE_LUN; + break; + case 'w': + f |= US_FL_NO_WP_DETECT; + break; + /* Ignore unrecognized flag characters */ + } + } + us->fflags = (us->fflags & ~mask) | f; + dev_info(&us->pusb_intf->dev, "Quirks match for " + "vid %04x pid %04x: %x\n", + vid, pid, f); } /* Find an unusual_dev descriptor (always succeeds in the current code) */ @@ -1092,88 +1138,11 @@ static struct usb_driver usb_storage_driver = { .soft_unbind = 1, }; -/* Works only for digits and letters, but small and fast */ -#define TOLOWER(x) ((x) | 0x20) - -static void __init parse_quirks(void) -{ - int n, i; - char *p; - - if (!quirks) - return; - - /* Count the ':' characters to get 2 * the number of entries */ - n = 0; - for (p = quirks; *p; ++p) { - if (*p == ':') - ++n; - } - n /= 2; - if (n == 0) - return; /* Don't allocate 0 bytes */ - - quirks_list = kmalloc(n * sizeof(*quirks_list), GFP_KERNEL); - if (!quirks_list) - return; - - p = quirks; - quirks_end = quirks_list; - for (i = 0; i < n && *p; ++i) { - unsigned f = 0; - - /* Each entry consists of VID:PID:flags */ - quirks_end->vid = simple_strtoul(p, &p, 16); - if (*p != ':') - goto skip_to_next; - quirks_end->pid = simple_strtoul(p+1, &p, 16); - if (*p != ':') - goto skip_to_next; - - while (*++p && *p != ',') { - switch (TOLOWER(*p)) { - case 'c': - f |= US_FL_FIX_CAPACITY; - break; - case 'i': - f |= US_FL_IGNORE_DEVICE; - break; - case 'l': - f |= US_FL_NOT_LOCKABLE; - break; - case 'm': - f |= US_FL_MAX_SECTORS_64; - break; - case 'r': - f |= US_FL_IGNORE_RESIDUE; - break; - case 's': - f |= US_FL_SINGLE_LUN; - break; - case 'w': - f |= US_FL_NO_WP_DETECT; - break; - /* Ignore unrecognized flag characters */ - } - } - quirks_end->fflags = f; - ++quirks_end; - - skip_to_next: - /* Entries are separated by commas */ - while (*p) { - if (*p++ == ',') - break; - } - } /* for (i = 0; ...) */ -} - static int __init usb_stor_init(void) { int retval; printk(KERN_INFO "Initializing USB Mass Storage driver...\n"); - parse_quirks(); /* register the driver, return usb_register return code if error */ retval = usb_register(&usb_storage_driver); -- cgit v1.2.3 From 0d695913b0016b362a84a8bb6d6e28f8d90a70e2 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Sat, 20 Dec 2008 16:57:32 -0800 Subject: wimax: documentation for the stack wimax documentation Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- Documentation/wimax/README.wimax | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 Documentation/wimax/README.wimax (limited to 'Documentation') diff --git a/Documentation/wimax/README.wimax b/Documentation/wimax/README.wimax new file mode 100644 index 000000000000..b78c4378084e --- /dev/null +++ b/Documentation/wimax/README.wimax @@ -0,0 +1,81 @@ + + Linux kernel WiMAX stack + + (C) 2008 Intel Corporation < linux-wimax@intel.com > + + This provides a basic Linux kernel WiMAX stack to provide a common + control API for WiMAX devices, usable from kernel and user space. + +1. Design + + The WiMAX stack is designed to provide for common WiMAX control + services to current and future WiMAX devices from any vendor. + + Because currently there is only one and we don't know what would be the + common services, the APIs it currently provides are very minimal. + However, it is done in such a way that it is easily extensible to + accommodate future requirements. + + The stack works by embedding a struct wimax_dev in your device's + control structures. This provides a set of callbacks that the WiMAX + stack will call in order to implement control operations requested by + the user. As well, the stack provides API functions that the driver + calls to notify about changes of state in the device. + + The stack exports the API calls needed to control the device to user + space using generic netlink as a marshalling mechanism. You can access + them using your own code or use the wrappers provided for your + convenience in libwimax (in the wimax-tools package). + + For detailed information on the stack, please see + include/linux/wimax.h. + +2. Usage + + For usage in a driver (registration, API, etc) please refer to the + instructions in the header file include/linux/wimax.h. + + When a device is registered with the WiMAX stack, a set of debugfs + files will appear in /sys/kernel/debug/wimax:wmxX can tweak for + control. + +2.1. Obtaining debug information: debugfs entries + + The WiMAX stack is compiled, by default, with debug messages that can + be used to diagnose issues. By default, said messages are disabled. + + The drivers will register debugfs entries that allow the user to tweak + debug settings. + + Each driver, when registering with the stack, will cause a debugfs + directory named wimax:DEVICENAME to be created; optionally, it might + create more subentries below it. + +2.1.1. Increasing debug output + + The files named *dl_* indicate knobs for controlling the debug output + of different submodules of the WiMAX stack: + * +# find /sys/kernel/debug/wimax\:wmx0 -name \*dl_\* +/sys/kernel/debug/wimax:wmx0/wimax_dl_stack +/sys/kernel/debug/wimax:wmx0/wimax_dl_op_rfkill +/sys/kernel/debug/wimax:wmx0/wimax_dl_op_reset +/sys/kernel/debug/wimax:wmx0/wimax_dl_op_msg +/sys/kernel/debug/wimax:wmx0/wimax_dl_id_table +/sys/kernel/debug/wimax:wmx0/wimax_dl_debugfs +/sys/kernel/debug/wimax:wmx0/.... # other driver specific files + + NOTE: Of course, if debugfs is mounted in a directory other than + /sys/kernel/debug, those paths will change. + + By reading the file you can obtain the current value of said debug + level; by writing to it, you can set it. + + To increase the debug level of, for example, the id-table submodule, + just write: + +$ echo 3 > /sys/kernel/debug/wimax:wmx0/wimax_dl_id_table + + Increasing numbers yield increasing debug information; for details of + what is printed and the available levels, check the source. The code + uses 0 for disabled and increasing values until 8. -- cgit v1.2.3 From b0c83ae1de01880075955c7224e751440688ec74 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 23 Dec 2008 16:18:24 -0800 Subject: wimax: Makefile, Kconfig and docbook linkage for the stack This patch provides Makefile and KConfig for the WiMAX stack, integrating them into the networking stack's Makefile, Kconfig and doc-book templates. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- Documentation/DocBook/networking.tmpl | 8 ++++++++ net/Kconfig | 2 ++ net/Makefile | 1 + net/wimax/Kconfig | 38 +++++++++++++++++++++++++++++++++++ net/wimax/Makefile | 13 ++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 net/wimax/Kconfig create mode 100644 net/wimax/Makefile (limited to 'Documentation') diff --git a/Documentation/DocBook/networking.tmpl b/Documentation/DocBook/networking.tmpl index 627707a3cb9d..59ad69a9d777 100644 --- a/Documentation/DocBook/networking.tmpl +++ b/Documentation/DocBook/networking.tmpl @@ -74,6 +74,14 @@ !Enet/sunrpc/rpcb_clnt.c !Enet/sunrpc/clnt.c + WiMAX +!Enet/wimax/op-msg.c +!Enet/wimax/op-reset.c +!Enet/wimax/op-rfkill.c +!Enet/wimax/stack.c +!Iinclude/net/wimax.h +!Iinclude/linux/wimax.h + diff --git a/net/Kconfig b/net/Kconfig index 6ec2cce7c167..bf2776018f71 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -254,6 +254,8 @@ source "net/mac80211/Kconfig" endif # WIRELESS +source "net/wimax/Kconfig" + source "net/rfkill/Kconfig" source "net/9p/Kconfig" diff --git a/net/Makefile b/net/Makefile index ba4460432b7c..0fcce89d7169 100644 --- a/net/Makefile +++ b/net/Makefile @@ -63,3 +63,4 @@ endif ifeq ($(CONFIG_NET),y) obj-$(CONFIG_SYSCTL) += sysctl_net.o endif +obj-$(CONFIG_WIMAX) += wimax/ diff --git a/net/wimax/Kconfig b/net/wimax/Kconfig new file mode 100644 index 000000000000..0bdbb6928205 --- /dev/null +++ b/net/wimax/Kconfig @@ -0,0 +1,38 @@ +# +# WiMAX LAN device configuration +# + +menuconfig WIMAX + tristate "WiMAX Wireless Broadband support" + help + + Select to configure support for devices that provide + wireless broadband connectivity using the WiMAX protocol + (IEEE 802.16). + + Please note that most of these devices require signing up + for a service plan with a provider. + + The different WiMAX drivers can be enabled in the menu entry + + Device Drivers > Network device support > WiMAX Wireless + Broadband devices + + If unsure, it is safe to select M (module). + +config WIMAX_DEBUG_LEVEL + int "WiMAX debug level" + depends on WIMAX + default 8 + help + + Select the maximum debug verbosity level to be compiled into + the WiMAX stack code. + + By default, debug messages are disabled at runtime and can + be selectively enabled for different parts of the code using + the sysfs debug-levels file. + + If set at zero, this will compile out all the debug code. + + It is recommended that it is left at 8. diff --git a/net/wimax/Makefile b/net/wimax/Makefile new file mode 100644 index 000000000000..5b80b941c2c9 --- /dev/null +++ b/net/wimax/Makefile @@ -0,0 +1,13 @@ + +obj-$(CONFIG_WIMAX) += wimax.o + +wimax-y := \ + id-table.o \ + op-msg.o \ + op-reset.o \ + op-rfkill.o \ + stack.o + +wimax-$(CONFIG_DEBUG_FS) += debugfs.o + + -- cgit v1.2.3 From 3e91029ae049852c153da3fc355ab255ea7e2e0a Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Sat, 20 Dec 2008 16:57:42 -0800 Subject: i2400m: documentation and instructions for usage The driver for the i2400m is a stacked driver. There is a core driver, the bus-generic driver that has no knowledge or dependencies on how the device is connected to the system; it only knows how to speak the device protocol. Then there are the bus-specific drivers (for USB and SDIO) that provide backends for the generic driver to communicate with the device. The bus generic driver connects to the network and WiMAX stacks on the top side, and on the bottom to the bus-specific drivers. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- Documentation/wimax/README.i2400m | 260 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 Documentation/wimax/README.i2400m (limited to 'Documentation') diff --git a/Documentation/wimax/README.i2400m b/Documentation/wimax/README.i2400m new file mode 100644 index 000000000000..7dffd8919cb0 --- /dev/null +++ b/Documentation/wimax/README.i2400m @@ -0,0 +1,260 @@ + + Driver for the Intel Wireless Wimax Connection 2400m + + (C) 2008 Intel Corporation < linux-wimax@intel.com > + + This provides a driver for the Intel Wireless WiMAX Connection 2400m + and a basic Linux kernel WiMAX stack. + +1. Requirements + + * Linux installation with Linux kernel 2.6.22 or newer (if building + from a separate tree) + * Intel i2400m Echo Peak or Baxter Peak; this includes the Intel + Wireless WiMAX/WiFi Link 5x50 series. + * build tools: + + Linux kernel development package for the target kernel; to + build against your currently running kernel, you need to have + the kernel development package corresponding to the running + image installed (usually if your kernel is named + linux-VERSION, the development package is called + linux-dev-VERSION or linux-headers-VERSION). + + GNU C Compiler, make + +2. Compilation and installation + +2.1. Compilation of the drivers included in the kernel + + Configure the kernel; to enable the WiMAX drivers select Drivers > + Networking Drivers > WiMAX device support. Enable all of them as + modules (easier). + + If USB or SDIO are not enabled in the kernel configuration, the options + to build the i2400m USB or SDIO drivers will not show. Enable said + subsystems and go back to the WiMAX menu to enable the drivers. + + Compile and install your kernel as usual. + +2.2. Compilation of the drivers distributed as an standalone module + + To compile + +$ cd source/directory +$ make + + Once built you can load and unload using the provided load.sh script; + load.sh will load the modules, load.sh u will unload them. + + To install in the default kernel directories (and enable auto loading + when the device is plugged): + +$ make install +$ depmod -a + + If your kernel development files are located in a non standard + directory or if you want to build for a kernel that is not the + currently running one, set KDIR to the right location: + +$ make KDIR=/path/to/kernel/dev/tree + + For more information, please contact linux-wimax@intel.com. + +3. Installing the firmware + + The firmware can be obtained from http://linuxwimax.org or might have + been supplied with your hardware. + + It has to be installed in the target system: + * +$ cp FIRMWAREFILE.sbcf /lib/firmware/i2400m-fw-BUSTYPE-1.3.sbcf + + * NOTE: if your firmware came in an .rpm or .deb file, just install + it as normal, with the rpm (rpm -i FIRMWARE.rpm) or dpkg + (dpkg -i FIRMWARE.deb) commands. No further action is needed. + * BUSTYPE will be usb or sdio, depending on the hardware you have. + Each hardware type comes with its own firmware and will not work + with other types. + +4. Design + + This package contains two major parts: a WiMAX kernel stack and a + driver for the Intel i2400m. + + The WiMAX stack is designed to provide for common WiMAX control + services to current and future WiMAX devices from any vendor; please + see README.wimax for details. + + The i2400m kernel driver is broken up in two main parts: the bus + generic driver and the bus-specific drivers. The bus generic driver + forms the drivercore and contain no knowledge of the actual method we + use to connect to the device. The bus specific drivers are just the + glue to connect the bus-generic driver and the device. Currently only + USB and SDIO are supported. See drivers/net/wimax/i2400m/i2400m.h for + more information. + + The bus generic driver is logically broken up in two parts: OS-glue and + hardware-glue. The OS-glue interfaces with Linux. The hardware-glue + interfaces with the device on using an interface provided by the + bus-specific driver. The reason for this breakup is to be able to + easily reuse the hardware-glue to write drivers for other OSes; note + the hardware glue part is written as a native Linux driver; no + abstraction layers are used, so to port to another OS, the Linux kernel + API calls should be replaced with the target OS's. + +5. Usage + + To load the driver, follow the instructions in the install section; + once the driver is loaded, plug in the device (unless it is permanently + plugged in). The driver will enumerate the device, upload the firmware + and output messages in the kernel log (dmesg, /var/log/messages or + /var/log/kern.log) such as: + +... +i2400m_usb 5-4:1.0: firmware interface version 8.0.0 +i2400m_usb 5-4:1.0: WiMAX interface wmx0 (00:1d:e1:01:94:2c) ready + + At this point the device is ready to work. + + Current versions require the Intel WiMAX Network Service in userspace + to make things work. See the network service's README for instructions + on how to scan, connect and disconnect. + +5.1. Module parameters + + Module parameters can be set at kernel or module load time or by + echoing values: + +$ echo VALUE > /sys/module/MODULENAME/parameters/PARAMETERNAME + + To make changes permanent, for example, for the i2400m module, you can + also create a file named /etc/modprobe.d/i2400m containing: + +options i2400m idle_mode_disabled=1 + + To find which parameters are supported by a module, run: + +$ modinfo path/to/module.ko + + During kernel bootup (if the driver is linked in the kernel), specify + the following to the kernel command line: + +i2400m.PARAMETER=VALUE + +5.1.1. i2400m: idle_mode_disabled + + The i2400m module supports a parameter to disable idle mode. This + parameter, once set, will take effect only when the device is + reinitialized by the driver (eg: following a reset or a reconnect). + +5.2. Debug operations: debugfs entries + + The driver will register debugfs entries that allow the user to tweak + debug settings. There are three main container directories where + entries are placed, which correspond to the three blocks a i2400m WiMAX + driver has: + * /sys/kernel/debug/wimax:DEVNAME/ for the generic WiMAX stack + controls + * /sys/kernel/debug/wimax:DEVNAME/i2400m for the i2400m generic + driver controls + * /sys/kernel/debug/wimax:DEVNAME/i2400m-usb (or -sdio) for the + bus-specific i2400m-usb or i2400m-sdio controls). + + Of course, if debugfs is mounted in a directory other than + /sys/kernel/debug, those paths will change. + +5.2.1. Increasing debug output + + The files named *dl_* indicate knobs for controlling the debug output + of different submodules: + * +# find /sys/kernel/debug/wimax\:wmx0 -name \*dl_\* +/sys/kernel/debug/wimax:wmx0/i2400m-usb/dl_tx +/sys/kernel/debug/wimax:wmx0/i2400m-usb/dl_rx +/sys/kernel/debug/wimax:wmx0/i2400m-usb/dl_notif +/sys/kernel/debug/wimax:wmx0/i2400m-usb/dl_fw +/sys/kernel/debug/wimax:wmx0/i2400m-usb/dl_usb +/sys/kernel/debug/wimax:wmx0/i2400m/dl_tx +/sys/kernel/debug/wimax:wmx0/i2400m/dl_rx +/sys/kernel/debug/wimax:wmx0/i2400m/dl_rfkill +/sys/kernel/debug/wimax:wmx0/i2400m/dl_netdev +/sys/kernel/debug/wimax:wmx0/i2400m/dl_fw +/sys/kernel/debug/wimax:wmx0/i2400m/dl_debugfs +/sys/kernel/debug/wimax:wmx0/i2400m/dl_driver +/sys/kernel/debug/wimax:wmx0/i2400m/dl_control +/sys/kernel/debug/wimax:wmx0/wimax_dl_stack +/sys/kernel/debug/wimax:wmx0/wimax_dl_op_rfkill +/sys/kernel/debug/wimax:wmx0/wimax_dl_op_reset +/sys/kernel/debug/wimax:wmx0/wimax_dl_op_msg +/sys/kernel/debug/wimax:wmx0/wimax_dl_id_table +/sys/kernel/debug/wimax:wmx0/wimax_dl_debugfs + + By reading the file you can obtain the current value of said debug + level; by writing to it, you can set it. + + To increase the debug level of, for example, the i2400m's generic TX + engine, just write: + +$ echo 3 > /sys/kernel/debug/wimax:wmx0/i2400m/dl_tx + + Increasing numbers yield increasing debug information; for details of + what is printed and the available levels, check the source. The code + uses 0 for disabled and increasing values until 8. + +5.2.2. RX and TX statistics + + The i2400m/rx_stats and i2400m/tx_stats provide statistics about the + data reception/delivery from the device: + +$ cat /sys/kernel/debug/wimax:wmx0/i2400m/rx_stats +45 1 3 34 3104 48 480 + + The numbers reported are + * packets/RX-buffer: total, min, max + * RX-buffers: total RX buffers received, accumulated RX buffer size + in bytes, min size received, max size received + + Thus, to find the average buffer size received, divide accumulated + RX-buffer / total RX-buffers. + + To clear the statistics back to 0, write anything to the rx_stats file: + +$ echo 1 > /sys/kernel/debug/wimax:wmx0/i2400m_rx_stats + + Likewise for TX. + + Note the packets this debug file refers to are not network packet, but + packets in the sense of the device-specific protocol for communication + to the host. See drivers/net/wimax/i2400m/tx.c. + +5.2.3. Tracing messages received from user space + + To echo messages received from user space into the trace pipe that the + i2400m driver creates, set the debug file i2400m/trace_msg_from_user to + 1: + * +$ echo 1 > /sys/kernel/debug/wimax:wmx0/i2400m/trace_msg_from_user + +5.2.4. Performing a device reset + + By writing a 0, a 1 or a 2 to the file + /sys/kernel/debug/wimax:wmx0/reset, the driver performs a warm (without + disconnecting from the bus), cold (disconnecting from the bus) or bus + (bus specific) reset on the device. + +5.2.5. Asking the device to enter power saving mode + + By writing any value to the /sys/kernel/debug/wimax:wmx0 file, the + device will attempt to enter power saving mode. + +6. Troubleshooting + +6.1. Driver complains about 'i2400m-fw-usb-1.2.sbcf: request failed' + + If upon connecting the device, the following is output in the kernel + log: + +i2400m_usb 5-4:1.0: fw i2400m-fw-usb-1.3.sbcf: request failed: -2 + + This means that the driver cannot locate the firmware file named + /lib/firmware/i2400m-fw-usb-1.2.sbcf. Check that the file is present in + the right location. -- cgit v1.2.3